package cn.wenzy.aurora.framework.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import cn.wenzy.aurora.framework.bean.PageVO;
import cn.wenzy.aurora.framework.constant.IConstant;
import cn.wenzy.aurora.framework.response.ResponseCode;
import cn.wenzy.aurora.framework.response.ResponseResult;
import cn.wenzy.aurora.framework.support.i18n.I18nSupport;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@Slf4j
public class IController<S extends IService> implements IConstant {

    @Autowired
    protected I18nSupport i18n;
    @Autowired
    protected ServletContext servletContext;
    @Autowired
    protected S service;

    protected <T> IPage<T> toIPage(PageVO pageVO) {
        return toIPage(pageVO.getPageNo(), pageVO.getPageSize());
    }

    protected <T> IPage<T> toIPage(Map map) {
        Long pageNo = MapUtil.getLong(map, "pageNo");
        Long pageSize = MapUtil.getLong(map, "pageSize");
        return toIPage(pageNo, pageSize);
    }

    protected <T> IPage<T> toIPage(Long pageNo, Long pageSize) {
        long current = ObjectUtil.isNotNull(pageNo) && pageNo > ZERO ? pageNo : 1L;
        long size = ObjectUtil.isNotNull(pageSize) && pageSize > ZERO ? pageSize : 10L;
        return Page.of(current, size);
    }

    /**
     * 成功
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> success() {
        ResponseResult<T> result = new ResponseResult<>();
        result.setCode(ResponseCode.SUCCESS);
        result.setMessage(i18n.getMessage(I18N_MESSAGE.MESSAGE.SUCCESSFUL));
        return result;
    }

    /**
     * 成功
     * @param data
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> success(T data) {
        ResponseResult<T> result = success();
        result.setData(data);
        return result;
    }

    /**
     * 成功
     * @param page
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> success(IPage<?> page) {
        ResponseResult<T> result = success();
        result.setData((T) page.getRecords());
        result.setPage(new PageVO(page.getCurrent(), page.getSize(), page.getTotal(), page.getPages()));
        return result;
    }

    /**
     * 失败
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> fail() {
        ResponseResult<T> result = new ResponseResult<>();
        result.setCode(ResponseCode.FAIL);
        result.setMessage(i18n.getMessage(I18N_MESSAGE.MESSAGE.FAILED));
        return result;
    }

    /**
     * 失败
     * @param message
     * @param args
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> fail(String message, Object... args) {
        ResponseResult<T> result = fail();
        result.setMessage(i18n.getMessage(message, result.getMessage(), args));
        return result;
    }

    /**
     * 失败
     * @param data
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> fail(T data) {
        ResponseResult<T> result = fail();
        result.setData(data);
        return result;
    }

    /**
     * 失败
     * @param data
     * @return
     * @param <T>
     */
    protected <T> ResponseResult<T> fail(T data, String message, Object... args) {
        ResponseResult<T> result = fail(message, args);
        result.setData(data);
        return result;
    }


    /**
     * 下载
     * @param file
     * @param response
     */
    protected void download(@NotNull File file, @NotNull HttpServletResponse response) {
        download(file, file.getName(), response);
    }

    /**
     * 下载
     * @param file
     * @param fileName
     * @param response
     */
    protected void download(@NotNull File file, @NotBlank String fileName, @NotNull HttpServletResponse response) {
        try (InputStream is = new FileInputStream(file)) {
            download(is, fileName, response);
        } catch (Exception e) {
            log.error("文件下载失败", e);
        }
    }

    /**
     * 下载
     * @param is
     * @param fileName
     * @param response
     */
    protected void download(@NotNull InputStream is, @NotBlank String fileName, @NotNull HttpServletResponse response) {
        String encodeFileName = URLUtil.encode(fileName, StandardCharsets.UTF_8);
        try(ServletOutputStream os = response.getOutputStream()) {
            response.reset();
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + encodeFileName);
            IoUtil.copy(is, os, 1024);
        } catch (Exception e) {
            log.error("文件下载失败", e);
        }
    }

    /**
     * 预览，需自行判断文件是否支持预览
     * @param file
     * @param response
     */
    protected void preview(@NotNull File file, @NotNull HttpServletResponse response) {
        preview(file, file.getName(), response);
    }

    /**
     * 预览，需自行判断文件是否支持预览
     * @param file
     * @param fileName
     * @param response
     */
    protected void preview(@NotNull File file, @NotBlank String fileName, @NotNull HttpServletResponse response) {
        try (InputStream is = new FileInputStream(file)) {
            preview(is, fileName, response);
        } catch (Exception e) {
            log.error("文件下载失败", e);
        }
    }

    /**
     * 预览，需自行判断文件是否支持预览
     * @param is
     * @param fileName
     * @param response
     */
    protected void preview(@NotNull InputStream is, @NotBlank String fileName, @NotNull HttpServletResponse response) {
        String mediaType = servletContext.getMimeType(fileName);
        String encodeFileName = URLUtil.encode(fileName, StandardCharsets.UTF_8);
        try(ServletOutputStream os = response.getOutputStream()) {
            response.reset();
            response.setContentType(mediaType);
            response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + encodeFileName);
            IoUtil.copy(is, os, 1024);
        } catch (Exception e) {
            log.error("文件下载失败", e);
        }
    }

}
